package ru.alexbykov.nopaginate.paginate;

import ohos.agp.components.BaseItemProvider;
import ohos.agp.components.Component;
import ohos.agp.components.ListContainer;

import ru.alexbykov.nopaginate.callback.OnAdapterChangeListener;
import ru.alexbykov.nopaginate.callback.OnLoadMoreListener;
import ru.alexbykov.nopaginate.callback.OnRepeatListener;
import ru.alexbykov.nopaginate.item.ErrorItem;
import ru.alexbykov.nopaginate.item.LoadingItem;

/**
 * @author Alex Bykov and Marko Milos, original repository: https://github.com/MarkoMilos/Paginate
 */
public final class NoPaginate implements OnAdapterChangeListener, OnRepeatListener {
    private final int loadingTriggerThreshold;
    private final ListContainer recyclerView;
    private final OnLoadMoreListener loadMoreListener;
    private final LoadingItem loadingItem;
    private final ErrorItem errorItem;

    private WrapperAdapter wrapperAdapter;
    private WrapperAdapterObserver wrapperAdapterObserver;
    private BaseItemProvider userAdapter;

    private boolean isError;
    private boolean isLoading;
    private boolean isLoadedAllItems;

    private final Component.ScrolledListener scrolledListener
        = (component, scrollX, scrollY, oldScrollX, oldScrollY) -> checkScroll();

    NoPaginate(ListContainer recyclerView, OnLoadMoreListener loadMoreListener, int loadingTriggerThreshold,
        LoadingItem loadingItem, ErrorItem errorItem) {
        this.recyclerView = recyclerView;
        this.loadMoreListener = loadMoreListener;
        this.loadingTriggerThreshold = loadingTriggerThreshold;
        this.loadingItem = loadingItem;
        this.errorItem = errorItem;
        setupWrapper();
        setupScrollListener();
    }

    /**
     * 绑定ListContainer
     *
     * @param listContainer 绑定的ListContainer
     * @return NoPaginateBuilder
     */
    public static NoPaginateBuilder with(ListContainer listContainer) {
        return new NoPaginateBuilder(listContainer);
    }

    private void setupWrapper() {
        this.userAdapter = recyclerView.getItemProvider();
        wrapperAdapter = new WrapperAdapter(userAdapter, loadingItem, errorItem);
        wrapperAdapterObserver = new WrapperAdapterObserver(this, wrapperAdapter);
        userAdapter.addDataSubscriber(wrapperAdapterObserver);
        recyclerView.setItemProvider(wrapperAdapter);
        wrapperAdapter.setRepeatListener(this);
    }

    private void setupScrollListener() {
        recyclerView.setScrolledListener(scrolledListener);
    }

    private void checkAdapterState() {
        if (isCanLoadMore()) {
            if (loadMoreListener != null) {
                loadMoreListener.onLoadMore();
            }
        }
    }

    private boolean isCanLoadMore() {
        return !isLoading && !isError && !isLoadedAllItems;
    }

    @Override
    public void onAdapterChange() {
        recyclerView.getContext().getUITaskDispatcher().asyncDispatch(() -> {
            final PaginateStatus status = PaginateStatus.getStatus(isLoadedAllItems, isError);
            wrapperAdapter.stateChanged(status);
            checkScroll();
        });
    }

    private void checkScroll() {
        if (ScrollUtils.isOnBottom(recyclerView, loadingTriggerThreshold)) {
            checkAdapterState();
        }
    }

    /**
     * This method will show error on the bottom of your recyclerView.
     *
     * @param isShowError - true if show, false if hide
     */
    public void showError(boolean isShowError) {
        if (isShowError) {
            isError = true;
            wrapperAdapter.stateChanged(PaginateStatus.ERROR);
            ScrollUtils.fullScrollToBottom(recyclerView, wrapperAdapter);
        } else {
            isError = false;
        }
    }

    /**
     * This method will show error on the bottom of your recyclerView.
     *
     * @param show - true if show, false if hide
     */
    public void showLoading(boolean show) {
        if (show) {
            isLoading = true;
            wrapperAdapter.stateChanged(PaginateStatus.LOADING);
        } else {
            isLoading = false;
        }
    }

    /**
     * This method  show error on the bottom of your recyclerView.
     *
     * @param isNoMoreItems - true if items ended, false if no
     */
    public void setNoMoreItems(boolean isNoMoreItems) {
        if (isNoMoreItems) {
            this.isLoadedAllItems = true;
            wrapperAdapter.stateChanged(PaginateStatus.NO_MORE_ITEMS);
        } else {
            this.isLoadedAllItems = false;
        }
    }

    @Override
    public void onClickRepeat() {
        showError(false);
        checkScroll();
        ScrollUtils.fullScrollToBottom(recyclerView, wrapperAdapter);
    }

    /**
     * This method unsubscribe observer and change listeners reference to null
     * for avoid memory leaks.
     */
    public void unbind() {
        wrapperAdapter.unbind();
        userAdapter.removeDataSubscriber(wrapperAdapterObserver);
        recyclerView.setItemProvider(userAdapter);
    }
}

